#include "fs.h"
#include "string.h"
#include "common.h"
#include "stdio.h"

static super_block_t *super_block = NULL;

static fd_t fds[NUM_FD];
char buf[0x1000];
uint32_t used_inode_id = 0;
uint32_t used_datablk_id = 0;


void read_super_block()
{
    superblk = (super_block_t *)SUPER_BLK_ADDR;
    sd_card_read((void *)superblk, SUPER_BLK_SD_ADDR, SUPER_BLOCK_SIZE);
}


int do_open(char *name, uint32_t access)
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return -1;
    }
    int i, j, k;
    dir_entry_t *dir_entry_tmp;
    for (i = 0; i <= cur_inode->num; i++)
    {

        if (i == cur_inode->num){
            kprintf("[ERROR]:No Name! Will Create\n");
            do_touch(name);
        }
        j = i / 64;
        k = i % 64;
        if (k == 0)
        {
            sd_card_read((void *)buf, cur_inode->direct[j], BLOCK_SIZE);
            dir_entry_tmp = (dir_entry_t *)buf;
        }
        if (dir_entry_tmp[k].type == TYPE_FILE && !strcmp((char *)dir_entry_tmp[k].name, name))
        {
            int m = dir_entry_tmp[k].ino;
            sd_card_read((void *)(INODE_ADDR + BLOCK_SIZE * (m / 64)), INODE_SD_ADDR + BLOCK_SIZE * (m / 64), BLOCK_SIZE);
            if (inode[m].mode != access && inode[m].mode != O_RDWR)
                return -1; 
            m = alloc_fd(dir_entry_tmp[k].ino, access);
            return m;
        }
    }
}

int do_write(uint32_t fd, char *buff, uint32_t size)
{
    int k = fds[fd].ino;
    int i = fds[fd].w_cur_pos / BLOCK_SIZE;
    int left = 0;
    if (fds[fd].w_cur_pos % BLOCK_SIZE != 0)
    {
        bzero(buf, BLOCK_SIZE);
        if(inode[k].direct[i] == 0)
            inode[k].direct[i] = alloc_datablk();
        sd_card_read((void *)(buf), inode[k].direct[i], BLOCK_SIZE);
        if (BLOCK_SIZE - fds[fd].w_cur_pos % BLOCK_SIZE <= size)
        {
            memcpy(buf + fds[fd].w_cur_pos % BLOCK_SIZE, buff, BLOCK_SIZE - fds[fd].w_cur_pos % BLOCK_SIZE);
            fds[fd].w_cur_pos += BLOCK_SIZE - fds[fd].w_cur_pos % BLOCK_SIZE;
        }
        else
        {
            memcpy(buf + fds[fd].w_cur_pos % BLOCK_SIZE, buff, size);
            fds[fd].w_cur_pos += size;
        }
        sd_card_write((void *)(buf), inode[k].direct[i], BLOCK_SIZE);
        left += BLOCK_SIZE - fds[fd].w_cur_pos % BLOCK_SIZE;
        i++;
    }
    // a new block
    while (left < size)
    {
        bzero(buf, BLOCK_SIZE);
        if (inode[k].direct[i] == 0)
            inode[k].direct[i] = alloc_datablk();
        sd_card_read((void *)(buf), inode[k].direct[i], BLOCK_SIZE);
        memcpy(buf, buff + left, size - left);
        fds[fd].w_cur_pos += size - left;
        sd_card_write((void *)(buf), inode[k].direct[i], BLOCK_SIZE);
        i++;
        left += BLOCK_SIZE;
    }
    inode[k].num = (i > inode[k].num) ? i : inode[k].num;
    inode[k].used_sz += size;
    write_inode(inode[k].ino);
    return 1;
}



int do_read(uint32_t fd, char *buff, uint32_t size)
{
    int k = fds[fd].ino;
    if (inode[k].used_sz - fds[fd].r_cur_pos < size)
        return 0;
    int i = fds[fd].r_cur_pos / BLOCK_SIZE;
    int left = 0;
    // char *buf = (char *)DATA_BLK_ADDR;
    if (fds[fd].r_cur_pos % BLOCK_SIZE != 0)
    {
        bzero(buf, BLOCK_SIZE);
        sd_card_read((void *)(buf), inode[k].direct[i], BLOCK_SIZE);
        if (BLOCK_SIZE - fds[fd].r_cur_pos % BLOCK_SIZE <= size)
        {
            memcpy(buff, buf + fds[fd].r_cur_pos % BLOCK_SIZE, BLOCK_SIZE - fds[fd].r_cur_pos % BLOCK_SIZE);
            fds[fd].r_cur_pos += BLOCK_SIZE - fds[fd].r_cur_pos % BLOCK_SIZE;
        }
        else
        {
            memcpy(buff, buf + fds[fd].r_cur_pos % BLOCK_SIZE, size);
            fds[fd].r_cur_pos += size;
        }
        left += BLOCK_SIZE - fds[fd].r_cur_pos % BLOCK_SIZE;
        i++;
    }
    while (left < size)
    {
        bzero(buf, BLOCK_SIZE);
        sd_card_read((void *)(buf), inode[k].direct[i], BLOCK_SIZE);
        memcpy(buff + left, buf, size - left);
        fds[fd].r_cur_pos += size - left;
        i++;
        left += BLOCK_SIZE;
    }
    return 1;
}



int do_close(uint32_t fd)
{
    int k = fds[fd].ino;
    write_inode(inode[k].ino);
    bzero((char *)&fds[fd], sizeof(fds[fd]));
    return 0;
}

int do_cat(char *name)
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return -1;
    }
    int i, j, k;
    dir_entry_t *dir_entry_tmp;
    //check exists
    for (i = 0, j = 0; i < cur_inode->num; i++)
    {
        j = i / 64;
        k = i % 64;
        if (k == 0)
        {
            sd_card_read((void *)buf, cur_inode->direct[j], BLOCK_SIZE);
            dir_entry_tmp = (dir_entry_t *)buf;
        }
        if (dir_entry_tmp[k].type == 1 && !strcmp((char *)dir_entry_tmp[k].name, name))
        {
            int m = dir_entry_tmp[k].ino;
            sd_card_read((void *)(INODE_ADDR + BLOCK_SIZE * (m / 64)), INODE_SD_ADDR + BLOCK_SIZE * (m / 64), BLOCK_SIZE);
            char *buff = (char *)DATA_BLK_ADDR;
            for (j = 0; j < inode[m].num; j++)
            {
                bzero((char *)buff, BLOCK_SIZE);
                sd_card_read((void *)(buff), inode[m].direct[j], BLOCK_SIZE);
                for (k = 0; k < inode[m].used_sz - j * BLOCK_SIZE; k++)
                {
                    kprintf("%c", buff[k]);
                }
            }
            return 1;
        }
    }
    //No file
    return 0;
}

void do_init_fs()
{
    read_super_block();
    // not init yet
    if (superblk->magic_num != KFS_MAGIC)
    {
        do_mkfs();
        return;
    }
    //read block map
    blkmap = (uint8_t *)BMAP_ADDR;
    sd_card_read((void *)BMAP_ADDR, (uint32_t)BMAP_SD_ADDR, BMAP_SZ);
    //read inode map
    inodemap = (uint8_t *)IMAP_ADDR;
    sd_card_read((void *)IMAP_ADDR, (uint32_t)IMAP_SD_ADDR, IMAP_SZ);
    //read inodes
    inode_buf = (uint32_t *)INODE_ADDR;
    inode = (inode_entry_t *)INODE_ADDR;
    sd_card_read((void *)INODE_ADDR, (uint32_t)INODE_SD_ADDR, BLOCK_SIZE);
    used_inode_id = superblk->ino_alloc;
    used_datablk_id = superblk->blk_alloc;
    //current dir
    cur_inode = inode;
    dir_cur_dep = -1;
    bzero((void *)fds, sizeof(fds));
    return;
}

int do_mkfs()
{
    read_super_block();
   
    kprintf("[FS] Start initialize filesystem!          \n");
    kprintf("[FS] Setting superblock...                 \n");

    superblk->magic_num = KFS_MAGIC;
    superblk->fs_sz = FS_SIZE;        //256MB
    superblk->start_sector = 1048576; 
    superblk->blkmap_addr = BMAP_ADDR;
    superblk->blkmap_off = BMAP_SD_ADDR;

    superblk->imap_addr = IMAP_ADDR;
    superblk->imap_off = IMAP_SD_ADDR;

    superblk->inodes_addr = INODE_ADDR;
    superblk->inodes_off = INODE_SD_ADDR;
    
    superblk->datablock_addr = DATA_BLK_ADDR;
    superblk->datablock_off = DATA_BLK_SD_ADDR;
   
    superblk->inode_total_num = 0X1000;
    superblk->inode_free_num = superblk->inode_total_num;
    superblk->inode_free_num--; 
    superblk->ino_alloc = 1;
    superblk->blk_alloc = 0;

    superblk->datablk_total_num = DATA_BLOCK_SIZE / BLOCK_SIZE;
    superblk->datablk_free_num = superblk->datablk_total_num;
    // write back
    sd_card_write((void *)superblk, SUPER_BLK_SD_ADDR, SUPER_BLOCK_SIZE);

    // init inodemap
    kprintf("magic : %x                                       \n",superblk->magic_num);
    kprintf("num sector : 1048576 ,start_sector : 1048576     \n");
    kprintf("block map offset : 1  (32)                       \n");
    kprintf("inode map offset : 33 (1)                        \n");
    kprintf("inode offset :34 (512)                           \n");
    kprintf("data offset : 546 (1048030)                      \n");
    kprintf("inode entry size : 64 B                          \n");

    inodemap = (uint8_t *)IMAP_ADDR;
    bzero((void *)inodemap, superblk->inode_total_num / 8);
    sd_card_write((void *)inodemap, IMAP_SD_ADDR, superblk->inode_total_num / 8);

    kprintf("[FS] Setting block-map...                  \n");
    blkmap = (uint8_t *)BMAP_ADDR;
    bzero((void *)blkmap, superblk->datablk_total_num / 8);
    sd_card_write((void *)blkmap, BMAP_SD_ADDR, superblk->datablk_total_num / 8);

    kprintf("[FS] Setting inode...                      \n");
    inode_buf = (uint32_t *)INODE_ADDR;
    inode = (inode_entry_t *)INODE_ADDR;
    bzero((void *)inode_buf, INODES_SZ);
    used_inode_id = superblk->ino_alloc;
    used_datablk_id = superblk->blk_alloc;
    inode[0].ino = 0;
    inode[0].mode = O_RDWR;
    inode[0].used_sz = 8;
    inode[0].num = 2;

    //alloc datablock
    int i;
    for (i = 1; i < DIR_BLK_NUM; i++)
        inode[0].direct[i] = 0;
    inode[0].direct[0] = alloc_datablk();
    //write dentry
    init_entry(inode[0].direct[0], 0, 0);
    write_inode(0);
    dir_cur_dep = -1;
    kprintf("[FS] Initialize filesystem finished!       \n");
    cur_inode = inode;
    return 1;
}

void do_statfs()
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return;
    }
    
    uint32_t used_block = superblk->datablk_total_num - superblk->datablk_free_num;
    uint32_t used_inodes = superblk->inode_total_num - superblk->inode_free_num;

    kprintf("magic : %x (KFS)\n", superblk->magic_num);
    kprintf("used block: %d/%d, start sector: 0x%d(%x)\n",used_block, superblk->datablk_total_num, superblk->start_sector, superblk->start_sector);
    kprintf("block map offset: 1, occupied block: 32\n");
    kprintf("inode map offset: 33, occupied sector: 1, used: %d/%d\n",used_inodes, superblk->inode_total_num);
    kprintf("inode offset: 34, occupied block: 512\n");
    kprintf("data offset: 546, occupied block: 1048030\n");
    kprintf("entry size: %dB\n", sizeof(dir_entry_t));
}

int do_mkdir(char *name)
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return -1;
    }
    int i = 0;
    int j, k;
    dir_entry_t *dir_entry_temp;
    do
    {
        j = i / 64;
        k = i % 64;
        if (k == 0)
        {
            sd_card_read((void *)buf, cur_inode->direct[j], BLOCK_SIZE);
            dir_entry_temp = (dir_entry_t *)buf;
        }
        if (dir_entry_temp[k].type == TYPE_DIR && !strcmp((char *)dir_entry_temp[k].name, name)){
            kprintf("Already Exist!\n");
            return 0;
        }
        i++;
    } while (i <= cur_inode->num);

    strcpy((char *)dir_entry_temp[k].name, name);
    dir_entry_temp[k].type = TYPE_DIR;
    dir_entry_temp[k].ino = alloc_inode();
    
    cur_inode->num++;
    write_inode(cur_inode->ino);
    sd_card_write((void *)buf, cur_inode->direct[j], BLOCK_SIZE);
    //initialize the new dentry
    i = dir_entry_temp[k].ino;
    inode[i].mode = O_RDWR;
    inode[i].ino = i;
    inode[i].used_sz = 4;
    inode[i].num = 2; 
    inode[i].direct[0] = alloc_datablk();
    for (j = 1; j < DIR_BLK_NUM; j++)
        inode[i].direct[j] = 0;
    init_entry(inode[i].direct[0], i, cur_inode->ino);
    write_inode(i);
    return 1;
}

int do_rmdir(char *name)
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return -1;
    }
    int i, j, k;
    dir_entry_t *dir_entry_temp;
    for (i = 0; i < cur_inode->num; i++)
    {
        j = i / 64;
        k = i % 64;
        if (k == 0)
        {
            sd_card_read((void *)buf, cur_inode->direct[j], BLOCK_SIZE);
            dir_entry_temp = (dir_entry_t *)buf;
        }
        if (dir_entry_temp[k].type == 2 && !strcmp((char *)dir_entry_temp[k].name, name))
        {
            free_inode(dir_entry_temp[k].ino);
            dir_entry_temp[k].name[0] = '\0';
            dir_entry_temp[k].type = 0;
            dir_entry_temp[k].ino = -1;
            write_block(buf, cur_inode->direct[j]);
            cur_inode->used_sz -= 4;
            write_inode(cur_inode->ino);
            return 1;
        }
    }
    return 0;
}

int do_cd(char *dir)
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return -1;
    }
    inode_entry_t *cur_dir;
    int dep_temp;
    char path_temp[4][MAX_NAME_LEN];
    dir_entry_t *dir_entry_temp;

    int num, i, j, k, n, m;
    char bdir[4][MAX_NAME_LEN];
    int len = strlen(dir);
    if(len==0)
        return 0;
  
    dep_temp =( dir[0] == '/') ? -1 : dir_cur_dep;
    // char path_temp[4][MAX_NAME_LEN];
    for (n = 0; n < 4; n++)
        strcpy((char *)path_temp[n], (char *)path[n]);
    //directory structure
    cur_dir = dir[0] == '/' ? &inode[0] : cur_inode;
    //split the directory
    split(&num, bdir, dir);
    int find;
    for (n = 0; n < num; n++)
    {
        find = 0;
        if (!strcmp(bdir[n], "."))
            continue;
        if (!strcmp(bdir[n], ".."))
        {
            if (dep_temp <= -1)
                continue;
            sd_card_read((void *)buf, cur_dir->direct[0], BLOCK_SIZE);
            dir_entry_temp = (dir_entry_t *)buf;
            m = dir_entry_temp[1].ino;
            sd_card_read((void *)(INODE_ADDR + BLOCK_SIZE * (m / 64)), INODE_SD_ADDR + BLOCK_SIZE * (m / 64), BLOCK_SIZE);
            cur_dir = &inode[m];
            path_temp[dep_temp][0] = '\0';
            dep_temp--;
            continue;
        }
        for (i = 0; i < cur_dir->num; i++)
        {
            j = i / 64;
            k = i % 64;
            if (k == 0)
            {
                sd_card_read((void *)buf, cur_dir->direct[j], BLOCK_SIZE);
                dir_entry_temp = (dir_entry_t *)buf;
            }
            if (dir_entry_temp[k].type == TYPE_DIR && !strcmp((char *)dir_entry_temp[k].name, bdir[n]))
            {
                m = dir_entry_temp[k].ino;
                sd_card_read((void *)(INODE_ADDR + BLOCK_SIZE * (m / 64)), INODE_SD_ADDR + BLOCK_SIZE * (m / 64), BLOCK_SIZE);
                cur_dir = &inode[m];
                dep_temp++;
                strcpy((char *)path_temp[dep_temp], bdir[n]);
                find = 1;
                break;
            }
        }
        if (find == 0)
            return 0;
    }

    cur_inode = cur_dir;
    dir_cur_dep = dep_temp;
    for (n = 0; n < 4; n++)
        strcpy((char *)path[n], (char *)path_temp[n]);
    return 1;
}

// int do_ls(){
//     dir_entry_t *dir_entry_temp;
//     if(superblk->magic_num != KFS_MAGIC){
//         kprintf("[ERROR] No File System!\n");
//         return -1;
//     }
//     int i, j, k;
//     for(i = 0; i < cur_inode->num; i++){
//         j = i / 64;
//         k = i % 64;
//         if(k == 0){
//             sd_card_read((void *)buf, cur_inode->direct[j], 0x1000);
//             dir_entry_temp = (dir_entry_t *)buf;
//         }
//     }
//     for(i = 0; i < cur_inode->num; i++){
//         if(dir_entry_temp[i].name[0] != '\0'){
//             kprintf("%s\n",dir_entry_temp[i]);
//         }
//     }
//     //cur_inode = &inode[cur_inode->ino];
//     return 0;
// }

int do_ls(void)
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return -1;
    }
    inode_entry_t *cur_dir = cur_inode;
    print(cur_dir);
    return 1;
}

void print(inode_entry_t *cur_dir)
{
    dir_entry_t *dir_entry_temp;
    int i, j, k, p;
    for (i = 0; i < cur_dir->num; i++)
    {
        j = i / 64;
        k = i % 64;
        if(cur_dir->direct[j]==0)
            continue;
        sd_card_read((void *)buf, cur_dir->direct[j], BLOCK_SIZE);
        dir_entry_temp = (dir_entry_t *)buf;
        if (dir_entry_temp[k].ino == -1)
            continue;
        kprintf("%s \n", dir_entry_temp[k].name);
        uint32_t new_ino = dir_entry_temp[k].ino;
        if (k > 1 && dir_entry_temp[k].type == TYPE_DIR && new_ino > cur_dir->ino)
            print(&inode[new_ino]);
        k++;
    }
}

int do_touch(char *name)
{
    if (superblk->magic_num != KFS_MAGIC)
    {
        kprintf("[ERROR] No File System!\n");
        return -1;
    }
    int i = 0, j, k;
    dir_entry_t *dir_entry_tmp;
    do
    {
        j = i / 64;
        k = i % 64;
        if (k == 0)
        {
            sd_card_read((void *)buf, cur_inode->direct[j], BLOCK_SIZE);
            dir_entry_tmp = (dir_entry_t *)buf;
        }
        if (dir_entry_tmp[k].type == TYPE_FILE && !strcmp((char *)dir_entry_tmp[k].name, name))
        {
            kprintf("Already Exist!\n");
            return 0; 
        }
        i++;
    } while (i <= cur_inode->num);
  
    strcpy((char *)dir_entry_tmp[k].name, name);
    dir_entry_tmp[k].type = TYPE_FILE;
    dir_entry_tmp[k].ino = alloc_inode();
    cur_inode->num++;
    write_inode(cur_inode->ino);
    sd_card_write((void *)buf, cur_inode->direct[j], BLOCK_SIZE);

    //initialize the new dentry
    i = dir_entry_tmp[k].ino;
    inode[i].mode = O_RDWR;
    inode[i].ino = i;
    inode[i].used_sz = 0;
    inode[i].num = 0;
    inode[i].direct[0] = alloc_datablk();
    for (j = 1; j < DIR_BLK_NUM; j++)
        inode[i].direct[j] = 0;
    write_inode(i);
    bzero(buf, sizeof(buf));
    sd_card_write((void *)buf, inode[i].direct[0], BLOCK_SIZE);
    return 1;
}

void do_cfs()
{
    bzero((char *)superblk, 512);
    sd_card_write((void *)superblk, SUPER_BLK_SD_ADDR, 512);
    kprintf("The file system was removed!\n");
}

void init_entry(uint32_t sd_addr, uint32_t used_ino, uint32_t par_ino)
{
    bzero(buf, sizeof(buf));
    dir_entry_t *entry = (dir_entry_t *)buf;
    strcpy((char *)entry[0].name, (char *)".");
    entry[0].type = TYPE_ME;
    entry[0].ino = used_ino;
    strcpy((char *)entry[1].name, (char *)"..");
    entry[1].type = TYPE_FA;
    entry[1].ino = par_ino;
    sd_card_write((void *)buf, sd_addr, BLOCK_SIZE);
}

void write_inode(uint32_t ino)
{
    uint32_t block_offset = BLOCK_SIZE * ((ino) / 64);
    sd_card_write((void *)(INODE_ADDR + block_offset), INODE_SD_ADDR + block_offset, BLOCK_SIZE);
}

void write_block(void *memory_addr, uint32_t sd_addr)
{
    sd_card_write(memory_addr, sd_addr, BLOCK_SIZE);
}

void CLEAR_BMAP(uint32_t sd_addr)
{
    uint32_t block_offset = (sd_addr - DATA_BLK_SD_ADDR) / BLOCK_SIZE;
    blkmap[block_offset / 8] &= ~(1 << (block_offset % 8));
    // align by sector
    uint64_t write_bmap_addr = (BMAP_ADDR + block_offset / 8) & ALIGN_BY_SECTOR;
    sd_card_write((void *)write_bmap_addr, BMAP_SD_ADDR, SECTOR_SIZE);
}

void free_inode(int ino)
{
    int i;
    for (i = 0; i < DIR_BLK_NUM; i++)
    {
        if (inode[ino].direct[i] != 0)
            CLEAR_BMAP(inode[ino].direct[i]);
    }
    inodemap[ino / 8] &= ~(1 << ino % 8);
    sd_card_write((void *)IMAP_ADDR, IMAP_SD_ADDR, SECTOR_SIZE);
    superblk->inode_free_num++;
    sd_card_write((void *)SUPER_BLK_ADDR, SUPER_BLK_SD_ADDR, SECTOR_SIZE);
}

void split(int *argc, char argv[][MAX_NAME_LEN], char *cmd)
{
    int j = 0, k = 0, temp = 0;
    int len = strlen(cmd);
    if (len == 0 || (len == 1 && cmd[0] == '/'))
    {
        *argc = 0;
        return;
    }
    if (cmd[len - 1] != '/')
    {
        cmd[len] = '/';
        cmd[++len] = '\0';
    }
    if (cmd[j] == '/')
        j++;
    for (; j < len; j++)
    {
        if (cmd[j] == '/')
        {
            argv[temp][k] = '\0';
            temp++;
            k = 0;
        }
        else
            argv[temp][k++] = cmd[j];
    }
    *argc = temp;
}

uint32_t alloc_datablk()
{
    uint32_t i = used_datablk_id++;
    blkmap[i / 8] = blkmap[i / 8] | (1 << (i % 8));
    sd_card_write((void *)((uint64_t)(blkmap + (i / 8)) & ALIGN_BY_SECTOR), (BMAP_SD_ADDR + i / 8) & ALIGN_BY_SECTOR, SECTOR_SIZE);
    uint32_t addr = DATA_BLK_SD_ADDR + i * BLOCK_SIZE;
    superblk->blk_alloc++;
    superblk->datablk_free_num--;
    sd_card_write((void *)SUPER_BLK_ADDR, SUPER_BLK_SD_ADDR, SECTOR_SIZE);
    return addr;
}

uint32_t alloc_inode()
{
    uint32_t i = used_inode_id;
    inodemap[i / 8] = inodemap[i / 8] & (1 << (i % 8));
    sd_card_write((void *)inodemap, IMAP_SD_ADDR, SECTOR_SIZE);
    uint64_t addr = INODE_ADDR + BLOCK_SIZE * (i / 64);
    uint32_t sd_addr = INODE_SD_ADDR + BLOCK_SIZE * (i / 64);
    sd_card_read((void *)addr, sd_addr, BLOCK_SIZE);
    used_inode_id++;
    superblk->ino_alloc++;
    superblk->inode_free_num--;
    sd_card_write((void *)SUPER_BLK_ADDR, SUPER_BLK_SD_ADDR, SECTOR_SIZE);
    bzero(inode[i].direct, sizeof(inode[i].direct));
    inode[i].num = inode[i].mode = inode[i].ino = 0;
    return i;
}

int alloc_fd(uint32_t ino, uint32_t access)
{
    int i;
    for (i = 0; i < NUM_FD; i++)
        if (fds[i].ino == 0)
        {
            fds[i].ino = ino;
            fds[i].r_cur_pos = 0;
            fds[i].w_cur_pos = 0;
            fds[i].access = access;
            return i;
        }
    return -1;
}
